package com.itjeffrey.autocode.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itjeffrey.autocode.constant.SysConstant;
import com.itjeffrey.autocode.enums.ExceptionEnum;
import com.itjeffrey.autocode.exception.ACException;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Parser Util
 */
@Slf4j
public class ParserUtil {

    /**
     * xml suffix list
     */
    private static List<String> XML_SUFFIX_LIST = new ArrayList<String>(){{
        add(SysConstant.XML_SUFFIX);
    }};

    /**
     * word suffix list
     */
    private static List<String> WORD_SUFFIX_LIST = new ArrayList<String>(){{
        add(SysConstant.WORD_SUFFIX);
        add(SysConstant.WORDX_SUFFIX);
    }};

    /**
     * excel suffix list
     */
    private static List<String> EXCEL_SUFFIX_LIST = new ArrayList<String>(){{
        add(SysConstant.EXCEL_SUFFIX);
        add(SysConstant.EXCELX_SUFFIX);
    }};

    /**
     * freemarker template suffix
     */
    private static String FREEMARKER_SUFFIX = SysConstant.MODEL_FILE_SUFFIX;

    /**
     * freemarker configuration and version
     */
    private static final Configuration FREEMARKER_CONFIGURATION = new Configuration(Configuration.VERSION_2_3_20);

    /**
     * static init the freemarker configuration
     */
    static {
        FREEMARKER_CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(ParserUtil.class, "/templates"));
        FREEMARKER_CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        FREEMARKER_CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
        FREEMARKER_CONFIGURATION.setDefaultEncoding(SysConstant.UTF_8);
    }

    /**
     * dom4j parse XML
     * eg:
             <Users>
                <user>
                    <id>1</id>
                    <name>Jeffrey</name>
                    <age>25</age>
                </user>
                <user>
                     <id>2</id>
                     <name>Qiutee</name>
                     <age>25</age>
                </user>
                <user>
                     <id>3</id>
                     <name>Peat</name>
                     <age>18</age>
                </user>
             </Users>

     * @param xmlPath xml path
     * @param <T> tClass
     * @return
     */
    public static <T> T parseXML2Obj(String xmlPath, Class<T> tClass) throws Exception {
        File xmlFile = new File(xmlPath);
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(xmlFile);
        Element rootElement = document.getRootElement();
        Iterator iterator = rootElement.elementIterator();
        JSONArray jsonArray = new JSONArray();
        while (iterator.hasNext()){
            Element element = (Element) iterator.next();
            Iterator iterator1 = element.elementIterator();
            while (iterator1.hasNext()) {
                Element attribute = (Element) iterator1.next();
                String name = attribute.getName();
                String value = attribute.getStringValue();
                JSONObject jsonObject = new JSONObject(true);
                jsonObject.put(name, value);
                jsonArray.add(jsonObject);
            }
        }
        String rootName = rootElement.getName();
        JSONObject outerJO = new JSONObject();
        outerJO.put(rootName, jsonArray);
        return outerJO.toJavaObject(tClass);
    }

    /**
     * parse freemarker templates, convert to template string for output
     * @param map dataModel
     * @param templateName name
     * @return
     */
    public static String parseFTL2Str(Map<String, Object> map, String templateName){
        try {
            StringWriter sw = new StringWriter();
            Template template = FREEMARKER_CONFIGURATION.getTemplate(templateName + FREEMARKER_SUFFIX);
            template.process(map, sw);
            return ACBaseUtil.removeBlank(sw.toString());
        }catch (IOException e){
            log.error("freemarker template get failed.");
            throw new ACException(ExceptionEnum.TEMPLATE_GET_ERROR);
        }catch (TemplateException e){
            log.error("freemarker template parse error, templateName:{}", templateName);
            throw new ACException(ExceptionEnum.TEMPLATE_PARSE_ERROR);
        }
    }

}
